package com.wuliang.generate.common.core.utils;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.wuliang.generate.common.core.adapter.json.GsonTypeAdapter;
import com.wuliang.generate.common.core.adapter.json.HibernateProxyTypeAdapter;
import com.wuliang.generate.common.core.basic.BaseVo;
import com.wuliang.generate.common.core.basic.BasicEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
 * 统一Json工具，方便调用
 *
 * @author 邬魉
 */
@Lazy
@Slf4j
public class JsonUtils {

    /**
     * 声明一个Gson对象常量
     */
    private static final Gson GSON = new GsonBuilder()
            .excludeFieldsWithoutExposeAnnotation()
            .registerTypeAdapter(Map.class, new GsonTypeAdapter())
            .registerTypeAdapter(new TypeToken<Map<String, Object>>() {
            }.getType(), new GsonTypeAdapter())
            .create();

    static {
        try {
            Class.forName("org.hibernate.proxy.HibernateProxy");
            GSON.newBuilder().registerTypeAdapterFactory(HibernateProxyTypeAdapter.FACTORY);
        } catch (ClassNotFoundException e) {
            log.debug("当前项目没有依赖JPA框架");
        }
    }

    /**
     * 对象转换成JSON格式字符串
     *
     * @param value 要转换成字符串的对象
     * @return JSON 字符串
     */
    public static String toJson(Object value) {
        return GSON.toJson(value);
    }

    /**
     * 对象转换成JSON格式字符串
     *
     * @param reader 要转换成字符串的输入流
     * @return JSON 字符串
     */
    public static String toJson(Reader reader) {
        return GSON.fromJson(reader, new TypeToken<String>() {
        }.getType());
    }

    /**
     * Json字符串转换成Map对象
     *
     * @param json Json字符串
     * @return Map集合
     */
    public static Map<String, Object> jsonToMap(String json) {
        return GSON.fromJson(json, new TypeToken<Map<String, Object>>() {
        }.getType());
    }

    /**
     * 将IO流中的数据转换成Map
     *
     * @param inputStream IO流
     * @return Map集合
     */
    public static Map<String, Object> jsonToMap(InputStream inputStream) {
        return jsonToMap(new InputStreamReader(inputStream));
    }

    /**
     * 将IO流中的数据转换成Map
     *
     * @param reader IO流
     * @return Map集合
     */
    public static Map<String, Object> jsonToMap(Reader reader) {
        return GSON.fromJson(reader, new TypeToken<Map<String, Object>>() {
        }.getType());
    }

    /**
     * 对象转Map
     *
     * @param data 要转换的对象
     * @return Map集合
     */
    public static Map<String, Object> objectToMap(Object data) {
        return jsonToMap(GSON.toJson(data));
    }

    /**
     * 将输入流转换成对应对象
     */
    public static <T> T inputStreamToObject(InputStream inputStream, Class<T> tClass) {
        return GSON.fromJson(new InputStreamReader(inputStream), tClass);
    }

    /**
     * 将读取流转换成对应对象
     */
    public static <T> T readerToObject(Reader reader, Class<T> tClass) {
        return GSON.fromJson(reader, tClass);
    }

    /**
     * 字符串转换成特定对象
     *
     * @param json   Json字符串
     * @param aClass 特定对象
     * @return 对象
     */
    public static <T> T jsonToObject(String json, Class<T> aClass) {
        return GSON.fromJson(json, aClass);
    }

    /**
     * 将Map转换成指定对象
     *
     * @param objectMap Map集合
     * @param aClass    对象
     * @return 对象
     */
    public static <T> T mapToObject(Map<String, Object> objectMap, Class<T> aClass) {
        return jsonToObject(GSON.toJson(objectMap), aClass);
    }

    /**
     * Json字符串转换成JsonElement
     *
     * @param json Json字符串
     * @return {@link JsonElement}
     */
    public static JsonElement jsonToJsonElement(String json) {
        return GSON.fromJson(json, JsonElement.class);
    }

    /**
     * Json字符串转换成List集合
     *
     * @return {@link List}
     */
    public static <T> List<T> toArray(String json) {
        return GSON.fromJson(json, new TypeToken<List<T>>() {
        }.getType());
    }

    /**
     * 是不是 {@link JsonObject} 对象
     *
     * @param json Json字符串
     * @return 是/否
     */
    public static boolean isObject(String json) {
        return jsonToJsonElement(json) instanceof JsonObject;
    }

    /**
     * 是集合对象？
     *
     * @param json Json字符串
     * @return 是/否
     */
    public static boolean isArray(String json) {
        return jsonToJsonElement(json) instanceof JsonArray;
    }

}
